package com.iflyings.android.dataconfig

import org.json.JSONException
import org.json.JSONObject
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileReader
import java.io.FileWriter
import java.io.IOException

internal object FileUtils {

    private fun getBackupPath(filePath: String): String {
        return "$filePath.bak"
    }

    private fun writeFile(filePath: String, callback: (FileOutputStream) -> Unit) {
        try {
            val backupFile = File(getBackupPath(filePath))
            if (backupFile.exists()) {
                backupFile.delete()
            }
            val currFile = File(filePath)
            if (currFile.exists()) {
                currFile.renameTo(backupFile)
            }
            FileOutputStream(currFile).use {
                callback(it)
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    private fun readFile(filePath: String, onChecked: (FileInputStream) -> Boolean) {
        try {
            val currFile = File(filePath)
            if (currFile.exists() && currFile.length() > 0) {
                FileInputStream(currFile).use {
                    if (onChecked(it)) {
                        return
                    }
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        try {
            val backupFile = File(getBackupPath(filePath))
            if (backupFile.exists() && backupFile.length() > 0) {
                FileInputStream(backupFile).use {
                    if (onChecked(it)) {
                        return
                    }
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun writeText(filePath: String, callback: (BufferedWriter) -> Unit) {
        try {
            val backupFile = File(getBackupPath(filePath))
            if (backupFile.exists()) {
                backupFile.delete()
            }
            val currFile = File(filePath)
            if (currFile.exists()) {
                currFile.renameTo(backupFile)
            }

            FileWriter(currFile).use { fileWriter ->
                BufferedWriter(fileWriter).use { bufferedWriter ->
                    callback(bufferedWriter)
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun readText(filePath: String, onChecked: (BufferedReader) -> Boolean) {
        try {
            val currFile = File(filePath)
            if (currFile.exists() && currFile.length() > 0) {
                FileReader(currFile).use { fileReader ->
                    BufferedReader(fileReader).use { bufferedReader ->
                        if (onChecked(bufferedReader)) {
                            return
                        }
                    }
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        try {
            val backupFile = File(getBackupPath(filePath))
            if (backupFile.exists() && backupFile.length() > 0) {
                FileReader(backupFile).use { fileReader ->
                    BufferedReader(fileReader).use { bufferedReader ->
                        if (onChecked(bufferedReader)) {
                            return
                        }
                    }
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun writeJSON(filePath: String, jsonObject: JSONObject) {
        writeFile(filePath) {
            it.write(jsonObject.toString().toByteArray())
        }
    }

    fun readJSON(filePath: String): JSONObject? {
        var jsonObject: JSONObject? = null
        readFile(filePath) {
            val length = it.available()
            if (length <= 0) {
                return@readFile false
            }
            val bytes = ByteArray(length)
            if (length != it.read(bytes)) {
                return@readFile false
            }
            try {
                jsonObject = JSONObject(String(bytes))
                return@readFile true
            } catch (e: JSONException) {
                e.printStackTrace()
            }
            return@readFile false
        }
        return jsonObject
    }

    fun mkdirs(dirFile: File): Boolean {
        if (dirFile.exists()) {
            return true
        }
        val parentFile = dirFile.parentFile ?: return false
        return if (parentFile.exists()) {
            dirFile.mkdirs()
        } else {
            mkdirs(parentFile)
        }
    }
}
